package org.altervista.cp.thinbcgen.proxy;

import java.lang.reflect.Constructor;

import org.altervista.cp.thinbcgen.AbstractGenerator;

@SuppressWarnings("unchecked")
public class ProxyGenerator extends AbstractGenerator {

	public ProxyGenerator(Class targetClass) {
		this(targetClass, null);
	}

	public ProxyGenerator(Class targetClass, ExceptionHandler eh) {
		super(targetClass, new Object[] { eh });

		_eh = eh == null ? new DefaultExceptionHandler() : eh;
	}

	public Object generate(Object source) {
		Class sourceClass = source.getClass();
		String sourceClassName = sourceClass.getName();
		String generatedClassName = _targetClass.getName()
				+ "_"
				+ sourceClassName
						.substring(sourceClassName.lastIndexOf('.') + 1)
				+ "_Proxy";
		generatedClassName = generatedClassName.replaceAll("\\$", "");
		Class generatedClass = ((ProxyGenerator) _realGen).getGeneratedClass(
				generatedClassName, new Object[] { source });
		try {
			return newInstance(generatedClass.getConstructor(new Class[] {
					Object.class, ExceptionHandler.class }), new Object[] {
					source, _eh });
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	public ExceptionHandler getExceptionHandler() {
		return _eh;
	}

	protected Constructor getGeneratorConstructor() {
		String packageName = ProxyGenerator.class.getPackage().getName();
		Constructor constructor = null;
		try {
			constructor = Class.forName(packageName + ".SunProxyGenerator")
					.getDeclaredConstructor(GENERATOR_PARAM_TYPES);
		} catch (Exception e) {
			try {
				constructor = Class.forName(
						packageName + ".ApacheProxyGenerator")
						.getDeclaredConstructor(GENERATOR_PARAM_TYPES);
			} catch (Exception ex) {
				throw new IllegalStateException(ex);
			}
		}
		constructor.setAccessible(true);
		return constructor;
	}

	protected String getGeneratedSuffix() {
		return "Proxy";
	}

	// protected Class _sourceClass;

	private ExceptionHandler _eh;

	private static final Class[] GENERATOR_PARAM_TYPES = new Class[] {
			Class.class, Object[].class };
}
